Skip to content

[4주차] 남유정/[feat] 게시물/댓글/신고 도메인 기반 기능 설계 및 API 구현#166

Open
N-yujeong wants to merge 2 commits intoLeets-Official:남유정/mainfrom
N-yujeong:남유정/4주차

Hidden character warning

The head ref may contain hidden characters: "\ub0a8\uc720\uc815/4\uc8fc\ucc28"
Open

[4주차] 남유정/[feat] 게시물/댓글/신고 도메인 기반 기능 설계 및 API 구현#166
N-yujeong wants to merge 2 commits intoLeets-Official:남유정/mainfrom
N-yujeong:남유정/4주차

Conversation

@N-yujeong
Copy link
Copy Markdown

1. 과제 요구사항 중 구현한 내용

  • 게시물 / 댓글 / 신고 도메인 활용
  • 단순 CRUD를 넘는 API 3개 이상 직접 설계 및 구현 (총 5개)
  • 도메인 상태(State) 변화 설계 (PostStatus: ACTIVE/HIDDEN, ReportStatus: PENDING/RESOLVED)
  • 동일 요청에 대한 중복 처리 방지 로직 구현
  • 권장 추가 구현 반영 (선택)

2. 핵심 변경 사항

신규 도메인 - Report

  • Report 엔티티: reporter(User), targetType(POST/COMMENT), targetId, reason,
    status(PENDING/RESOLVED)
  • (reporter_id, target_type, target_id) unique constraint로 DB 레벨 중복 신고 방지
  • ReportService: 게시글/댓글 신고, 신고 처리 완료(PENDING → RESOLVED)

기존 엔티티 수정

  • Post: PostStatus 필드 추가 (ACTIVE/HIDDEN), hide() 메서드
  • Comment: adopted 필드 추가, adopt() 메서드

예외 처리

  • 커스텀 예외 추가: UserNotFoundException, CategoryNotFoundException,
    AlreadyHiddenException, AlreadyResolvedException, DuplicateReportException,
    AlreadyAdoptedException
  • 기존 IllegalArgumentException 사용 부분 → 커스텀 예외로 통일

3. 실행 및 검증 결과

게시글 신고

게시글 신고 성공
image
게시글 중복 신고 실패 (409)
image

댓글 신고

댓글 신고 성공
image
댓글 중복 신고 실패 (409)
image

신고 처리 완료 (PENDING → RESOLVED)

신고 처리 성공
image
이미 처리된 신고 재처리 실패 (409)
image

게시글 숨김 (ACTIVE → HIDDEN)

게시글 숨김 성공
image
이미 숨김 처리된 게시글 실패 (409)
image
작성자 아닌 유저 숨김 시도 실패 (403)
image

댓글 작성

댓글 작성 성공
image

댓글 채택

댓글 채택 성공
image
중복 채택 실패 (409)
image
작성자 아닌 유저 채택 시도 실패 (403)
image

4. 완료 사항

  1. 게시글 신고 API 구현 (중복 신고 방지 포함)
  2. 댓글 신고 API 구현 (중복 신고 방지 포함)
  3. 신고 처리 완료 API 구현 (PENDING → RESOLVED 상태 변경)
  4. 게시글 숨김 API 구현 (ACTIVE → HIDDEN 상태 변경)
  5. 댓글 채택 API 구현 (게시글당 1개 제한)

5. 추가 사항

제출 체크리스트

  • PR 제목이 규칙에 맞다
  • base가 {이름}/main 브랜치다
  • compare가 {이름}/{숫자}주차 브랜치다
  • 프로젝트가 정상 실행된다
  • 본인을 Assignee로 지정했다
  • 파트 담당 Reviewer를 지정했다
  • 리뷰 피드백을 반영한 뒤 머지/PR close를 진행한다

Reviewer 참고

@N-yujeong N-yujeong requested a review from a team April 28, 2026 14:55
@N-yujeong N-yujeong self-assigned this Apr 28, 2026
Copy link
Copy Markdown

@gusanans218 gusanans218 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

댓글, 게시글, 신고를 각각 domain 단위로 분리해서 설계하신 점이 인상적이었습니다!!
특히 Report를 별도 도메인으로 분리하고 targetType으로 POST/COMMENT를 구분한 구조가 확장성을 잘 고려한 설계라고 느껴졍습니다!

Copy link
Copy Markdown

@Hanharam Hanharam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 계층을 잘 분리하면서 코드를 작성하신 점과 신고 중복 방지를 위해 DB에 제약을 설정하신 점이 좋았습니다!

Copy link
Copy Markdown

@jihoonkim501 jihoonkim501 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

유정님 수고 많으셨습니다~! 확실히 프론트를 하셨다보니까 스웨거 정리가 매우 깔끔하고 눈에 확들어오는 것 같아요 👍👍 제 코멘트만 확인해주시면 감사하겠습니다~!~!

Comment on lines +34 to +38
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "채택 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "해당 게시글의 댓글이 아님"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "채택 권한 없음 (게시글 작성자가 아님)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "게시글 또는 댓글 없음"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "이미 채택된 댓글 존재")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

역시 스웨거 문서관리 👍 👍 👍


// 해당 게시글의 댓글인지 확인
if (!comment.getPost().getId().equals(postId)) {
throw new IllegalArgumentException("해당 게시글에 속한 댓글이 아닙니다.");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 동일하게 커스텀 예외처리하는건 어떨까요~?!

import java.util.Map;

@Tag(name = "Post", description = "게시글 관련 API")
public interface PostControllerDocs {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs로 분기하는거 너무 좋습니다..👍 👍

Comment on lines +3 to +6
public enum PostStatus {
ACTIVE,
HIDDEN
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

만약 softDelete를 생각하신다면 Deleted 상태도 추가하는걸 추천드립니다~!

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ReportService {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

충분히 잘 구성해주셨습니다~! 추후에 리팩토링을 한다면 한 메소드에 검증, 저장, 예외를 던지는 책임이 과다할 수 있어서 분기하는 것 또한 추천드립니다! ( 오버엔지니어링이라고 생각된다면 괜찮습니다~!~!)

.body(ApiResponse.error("POST_NOT_FOUND", "해당 게시글을 찾을 수 없습니다."));
}

@ExceptionHandler(CommentNotFoundException.class)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

핸들러로 매번 추가하는것도 초반엔 괜찮을 수 있는데 프로젝트 규모가 커지면 조금 버거울 수 있습니다. ErrorCode 또는 status로 관리하는 방법도 있다는 점 알고계시면 좋을 것 같아요~!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants